/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.huawei.housekeeper.service.impl;

import com.huawei.housekeeper.controller.request.UserLoginDto;
import com.huawei.housekeeper.dao.entity.User;
import com.huawei.housekeeper.dao.mapper.UserMapper;
import com.huawei.housekeeper.enums.AccountTypeEnum;
import com.huawei.housekeeper.enums.ErrorCode;
import com.huawei.housekeeper.exception.Assert;
import com.huawei.housekeeper.service.UserLoginService;
import com.huawei.housekeeper.utils.JwtGenerateTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 用户登录
 *
 * @author y00464350
 * @since 2022-02-11
 */
@Service
@Qualifier("userDetailsService")
public class UserLoginServiceImpl implements UserLoginService, UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtGenerateTokenUtil jwtGenerateTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 用户登录接口
     *
     * @param userLoginDto 用户登录信息
     * @return token
     */
    @Override
    public String userLogin(UserLoginDto userLoginDto) {
        User user = userMapper.getByUserName(userLoginDto.getUserName());
        Assert.isFalse(user == null, ErrorCode.USER_EMPTY.getCode(), ErrorCode.USER_EMPTY.getMessage());
        // 校验登录角色类型
        AccountTypeEnum typeEnum = AccountTypeEnum.ofAccountType(userLoginDto.getAccountType())
                .orElseGet(() -> AccountTypeEnum.ACCOUNT_USER);
        Assert.isTrue(user.getAccountType() == typeEnum.getCode(),
                ErrorCode.USER_EMPTY.getCode(), ErrorCode.USER_EMPTY.getMessage());
        String userName = user.getUserName();
        String password = user.getPassword();
        // 校验密码
        Assert.isTrue(passwordEncoder.matches(userLoginDto.getPassword(), password),
                ErrorCode.USERNAME_OR_PASSWORD_ERROR.getCode(), ErrorCode.USERNAME_OR_PASSWORD_ERROR.getMessage());
        // 将产生的token对象给进行登录认证
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new
                UsernamePasswordAuthenticationToken(userName, null);
        // 将返回的Authentication对象给到当前的SecurityContext
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        return jwtGenerateTokenUtil.generateToken(user);
    }

    /**
     * spring security
     *
     * @param userName 用户名
     * @return userDetails
     * @throws UsernameNotFoundException 用户名为空
     */
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        Assert.notNull(userName, ErrorCode.PARAM_INVALID.getCode(), ErrorCode.PARAM_INVALID.getMessage());
        com.huawei.housekeeper.dao.entity.User userDatabase = userMapper.getByUserName(userName);

        Assert.notNull(userDatabase, ErrorCode.PARAM_INVALID.getCode(), ErrorCode.PARAM_INVALID.getMessage());
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_" + userDatabase.getUserRole());
        grantedAuthorityList.add(grantedAuthority);
        return new org.springframework.security.core.userdetails.User(userDatabase.getUserName(),
                userDatabase.getPassword(), grantedAuthorityList);
    }
}
